import socket
import threading

from PySide2.QtWidgets import QApplication, QFileDialog, QMdiSubWindow
from PySide2.QtUiTools import QUiLoader
from PySide2.QtCore import Qt,QSize
import qtawesome as qta

from share import SI, mySignals

from codehelper import Client,LoadTest
from monitor import Monitor


from lib.syntaxhighlighter import PythonHighlighter



class Win_Main:

    def __init__(self):
        # 从文件中加载UI定义
        self.ui_loader = QUiLoader()

        # 从 UI 定义中动态 创建一个相应的窗口对象
        # 注意：里面的控件对象也成为窗口对象的属性了
        # 比如 self.ui.button , self.ui.textEdit
        self.ui = self.ui_loader.load('ui/main.ui')

        self.ui.action_openProjectFolder.triggered.connect(self.action_openProjectFolder)

        self.ui.tb_logger.document().setMaximumBlockCount(1000)

        self.highlighter_logger = PythonHighlighter(self.ui.tb_logger.document())

        # 设置侧边栏图标
        self.ui.btn_client.setIcon(qta.icon('fa5.user', color='SteelBlue'))
        self.ui.btn_client.setIconSize(QSize(30, 30))

        self.ui.btn_loadtest.setIcon(qta.icon('fa5s.users',color='SteelBlue'))
        self.ui.btn_loadtest.setIconSize(QSize(32, 32) )
        #
        # self.ui.btn_expert.setIcon(qta.icon('fa5b.python',color='SteelBlue'))
        # self.ui.btn_expert.setIconSize(QSize(35, 35))

        self.ui.btn_monitor.setIcon(qta.icon('fa.tachometer',color='SteelBlue'))
        self.ui.btn_monitor.setIconSize(QSize(32, 32) )

        self.ui.btn_remote.setIcon(qta.icon('mdi.remote-desktop',color='SteelBlue'))
        self.ui.btn_remote.setIconSize(QSize(32, 32) )

        self.ui.btn_about.setIcon(qta.icon('mdi.help-circle-outline',color='SteelBlue'))
        self.ui.btn_about.setIconSize(QSize(32, 32) )


        #    定义侧边栏点击事件处理
        self.ui.btn_client.clicked.connect(self.loadClientSubWin)
        self.ui.btn_loadtest.clicked.connect(self.loadLoadTestSubWin)
        self.ui.btn_monitor.clicked.connect(self.loadMonitorSubWin)

        # 保存子窗口 的字典
        self.subWinTable = {}

        SI.logInfo = self.logInfo
        mySignals.stats_recved.connect(self.stats_recved)


        # 统计信息接收和处理
        self.runStatsRecvThread()


    def runStatsRecvThread(self):
        # 创建统计信息接收 UDP socket
        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

        for i in range(200):
            try:
                self.server_socket.bind(('',SI.listenPort))
                break
            except:
                SI.logInfo(f'绑定端口 {SI.listenPort} 失败!')
                SI.listenPort += 1
        else:
            SI.logInfo('未能找到合适的端口')
            return

        SI.logInfo(f'绑定端口 {SI.listenPort} 成功')
        self.ui.statusbar.showMessage(f'绑定端口 {SI.listenPort}')

        # 启动新线程，接收 压测进程的 实时统计信息
        self.statsRecvThread = threading.Thread(
            target=self.statsRecvThreadFunc,
            daemon=True)
        self.statsRecvThread.start()



    def statsRecvThreadFunc(self):
        while True:
            try:
                recvbytes, client_addr = self.server_socket.recvfrom(400)
                recvStr = recvbytes.decode()
                mySignals.stats_recved.emit(recvStr)
            except socket.timeout:
                continue

    def stats_recved(self,recvStr):
        SI.logInfo(recvStr)


    def _createSubWin(self,funcClass):
        subWinFuncObj = funcClass()
        mdiSubWin = QMdiSubWindow()
        mdiSubWin.setWidget(subWinFuncObj.ui)
        mdiSubWin.setAttribute(Qt.WA_DeleteOnClose)

        # 把子窗口加入到 MDI 区域
        self.ui.mdiArea.addSubWindow(mdiSubWin)
        # 存入表中，
        self.subWinTable[str(funcClass)] = {'mdiSubWin': mdiSubWin, 'subWinFuncObj': subWinFuncObj}

        # 显示子窗口
        mdiSubWin.show()
        # 子窗口提到最上层，并且最大化
        mdiSubWin.setWindowState(Qt.WindowActive | Qt.WindowMaximized)

    def _loadSubWin(self,funcClass):

        if not SI.projectPath:
            self.logInfo('请先设置项目目录！！！')
            return

        if str(funcClass) not in self.subWinTable:
            self._createSubWin(funcClass)
            return

        # 已经创建过字窗口，显示子窗口
        try:
            self.subWinTable[str(funcClass)]['mdiSubWin'].setWindowState(Qt.WindowActive | Qt.WindowMaximized)
        except:
            # 异常原因肯定是用户手动关闭了该窗口，subWin对象已经不存在了
            self._createSubWin(funcClass)

    def loadClientSubWin(self):
        self._loadSubWin(Client)


    def loadLoadTestSubWin(self):
        self._loadSubWin(LoadTest)

    def loadMonitorSubWin(self):
        self._loadSubWin(Monitor)


    def action_openProjectFolder(self):
        filePath = QFileDialog.getExistingDirectory(self.ui, "选择项目目录",r'd:\t1\loadtest2')
        if not filePath:
            return

        SI.projectPath = filePath
        self.ui.setWindowTitle(f'黑羽压测 - {filePath}')

    def onClearLog(self):
        self.ui.tb_logger.clear()

    def logInfo(self,info):
        self.ui.tb_logger.append(info)
        self.ui.tb_logger.ensureCursorVisible()


app = QApplication([])
winMain = Win_Main()
winMain.ui.show()
app.exec_()